{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Math behind LinearExplainer with correlation feature perturbation\n",
    "\n",
    "When we use `LinearExplainer(model, prior, feature_perturbation=\"correlation_dependent\")` we do not use $E[f(x) \\mid do(X_S = x_S)]$ to measure the impact of a set $S$ of features, but rather use $E[f(x) \\mid X_S = x_s]$ under the assumption that the random variable $X$ (representing the input features) follows a multivariate guassian distribution. To compute SHAP values this way we need to compute conditional expectations under the multivariate guassian distribution for all subset of features. This would be a lot of matrix match for an exponential number of terms, and it hence intractable for models with more than just a few features.\n",
    "\n",
    "This document briefly outlines the math we have used to precompute all of the required linear algebra using a sampling procedure that can be done just once, and then applied to as many samples as we like. This drastically speed up the computation compared to a brute force approach. Note that all these calculations depend on the fact that we are explaining a linear model $f(x) = \\beta x$."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The permutation definition of SHAP values in the interventional form used by most explainers is\n",
    "\n",
    "$$\n",
    "\\phi_i = \\frac{1}{M!} \\sum_R E[f(X) \\mid do(X_{S_i^R \\cup i} = x_{S_i^R \\cup i})] - E[f(X) \\mid do(X_{S_i^R} = x_{S_i^R})]\n",
    "$$\n",
    "\n",
    "but here we will use the non-interventional conditional expectation form (where we have simplified the notation by dropping the explicit reference to the random variable $X$).\n",
    "\n",
    "$$\n",
    "\\phi_i = \\frac{1}{M!} \\sum_R E[f(x) \\mid x_{S_i^R \\cup i}] - E[f(x) \\mid x_{S_i^R}]\n",
    "$$\n",
    "\n",
    "where $f(x) = \\beta x + b$ with $\\beta$ a row vector and $b$ a scalar."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we replace f(x) with the linear function definition we get:\n",
    "\n",
    "\\begin{align}\n",
    "\\phi_i = \\frac{1}{M!} \\sum_R E[\\beta x + b \\mid x_{S_i^R \\cup i}] - E[\\beta x + b \\mid x_{S_i^R}] \\\\\n",
    " = \\beta \\frac{1}{M!} \\sum_R E[x \\mid x_{S_i^R \\cup i}] - E[x \\mid x_{S_i^R}]\n",
    "\\end{align}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Assume the inputs $x$ follow a multivariate normal distribution with mean $\\mu$ and covariance $\\Sigma$. Denote the projection matrix that selects a set $S$ as $P_S$, then we get:\n",
    "\n",
    "\\begin{align}\n",
    "E[x \\mid x_S] = [P_{\\bar S} \\mu + P_{\\bar S} \\Sigma P_S^T (P_S \\Sigma P_S^T)^{-1} ( P_S x - P_S \\mu)] P_{\\bar S} + x P_S^T P_S \\\\\n",
    "= [P_{\\bar S} \\mu + P_{\\bar S} \\Sigma P_S^T (P_S \\Sigma P_S^T)^{-1} P_S (x - \\mu)] P_{\\bar S} + x P_S^T P_S \\\\\n",
    "= [\\mu + \\Sigma P_S^T (P_S \\Sigma P_S^T)^{-1} P_S (x - \\mu)] P_{\\bar S}^T P_{\\bar S} + x P_S^T P_S \\\\\n",
    "= P_{\\bar S}^T P_{\\bar S} [\\mu + \\Sigma P_S^T (P_S \\Sigma P_S^T)^{-1} P_S (x - \\mu)] + P_S^T P_S x \\\\\n",
    "= P_{\\bar S}^T P_{\\bar S} \\mu + P_{\\bar S}^T P_{\\bar S} \\Sigma P_S^T (P_S \\Sigma P_S^T)^{-1} P_S x - P_{\\bar S}^T P_{\\bar S} \\Sigma P_S^T (P_S \\Sigma P_S^T)^{-1} P_S \\mu + P_S^T P_S x \\\\\n",
    "= [P_{\\bar S}^T P_{\\bar S} - P_{\\bar S}^T P_{\\bar S} \\Sigma P_S^T (P_S \\Sigma P_S^T)^{-1} P_S] \\mu + [P_S^T P_S + P_{\\bar S}^T P_{\\bar S} \\Sigma P_S^T (P_S \\Sigma P_S^T)^{-1} P_S] x\n",
    "\\end{align}\n",
    "\n",
    "if we let $R_S = P_{\\bar S}^T P_{\\bar S} \\Sigma P_S^T (P_S \\Sigma P_S^T)^{-1} P_S$ and $Q_S = P_S^T P_S$ then we can write\n",
    "\n",
    "\\begin{align}\n",
    "E[x \\mid x_S] = [Q_{\\bar S} - R_S] \\mu + [Q_S + R_S] x\n",
    "\\end{align}\n",
    "\n",
    "or\n",
    "\n",
    "\\begin{align}\n",
    "E[x \\mid x_{S_i^R \\cup i}] = [Q_{\\bar{S_i^R \\cup i}} - R_{S_i^R \\cup i}] \\mu + [Q_{S_i^R \\cup i} + R_{S_i^R \\cup i}] x\n",
    "\\end{align}\n",
    "\n",
    "leading to the Shapley equation of\n",
    "\n",
    "\\begin{align}\n",
    "\\phi_i = \\beta \\frac{1}{M!} \\sum_R  [Q_{\\bar{S_i^R \\cup i}} - R_{S_i^R \\cup i}] \\mu + [Q_{S_i^R \\cup i} + R_{S_i^R \\cup i}] x - [Q_{\\bar{S_i^R}} - R_{S_i^R}] \\mu - [Q_{S_i^R} + R_{S_i^R}] x \\\\\n",
    "= \\beta \\frac{1}{M!} \\sum_R  ([Q_{\\bar{S_i^R \\cup i}} - R_{S_i^R \\cup i}] - [Q_{\\bar{S_i^R}} - R_{S_i^R}]) \\mu + ([Q_{S_i^R \\cup i} + R_{S_i^R \\cup i}] - [Q_{S_i^R} + R_{S_i^R}]) x \\\\\n",
    "= \\beta \\left [ \\frac{1}{M!} \\sum_R  ([Q_{\\bar{S_i^R \\cup i}} - R_{S_i^R \\cup i}] - [Q_{\\bar{S_i^R}} - R_{S_i^R}]) \\right ] \\mu + \\beta \\left [ \\frac{1}{M!} \\sum_R ([Q_{S_i^R \\cup i} + R_{S_i^R \\cup i}] - [Q_{S_i^R} + R_{S_i^R}]) \\right ] x\n",
    "\\end{align}\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$$\n",
    "\\phi = \\beta T x\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This means that we can precompute the transform matrix $T$ by drawing random permutations $R$ many times and averaging our results. Once we have computed $T$ we can explain any number of samples (or models for that matter) by just using matrix multiplication."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
